package com.hospital.hms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateRange;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.hospital.hms.common.OperationMessage;
import com.hospital.hms.dao.DoctorWorkPlanDao;
import com.hospital.hms.pojo.DoctorWorkPlan;
import com.hospital.hms.pojo.DoctorWorkPlanSchedule;
import com.hospital.hms.service.DoctorWorkPlanScheduleService;
import com.hospital.hms.service.DoctorWorkPlanService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@Slf4j
public class DoctorWorkPlanServiceImpl implements DoctorWorkPlanService {

    @Autowired
    DoctorWorkPlanDao doctorworkPlanDao;

    //    查询门诊日程出诊计划
    @Override
    public JSONArray selectWorkPlanByTime(Map param, ArrayList dateList) {
        ArrayList<HashMap> list = doctorworkPlanDao.selectWorkPlanByTime(param);
        Integer tempSubId = null;  //门诊日程出诊时间段
        String tempDate = null;
        HashMap tempResult = new HashMap<>();
        for (HashMap one : list) {
            String deptName = MapUtil.getStr(one, "deptName");
            Integer deptSubId = MapUtil.getInt(one, "deptSubId");
            String deptSubName = MapUtil.getStr(one, "deptSubName");
            String doctorName = MapUtil.getStr(one, "doctorName");
//            Integer workPlanId = MapUtil.getInt(one, "workPlanId");
            String date = MapUtil.getStr(one, "date");

            //判断是不是第一条记录
            if (tempSubId == null) {
                tempSubId = deptSubId;  //是第一条记录
                tempDate = date;
                //把这第一条记录当作一个诊室
                HashMap temp = new HashMap() {{
                    put("deptName", deptName);
                    put("deptSubId", deptSubId);
                    put("deptSubName", deptSubName);
//                    保证后续添加的顺序不被打乱，那这里的出诊计划必须是LinkedHashMap
                    put("plan", new LinkedHashMap<>() {{
                        put(date, new ArrayList<>() {{
                            add(doctorName);
                        }});
                    }});
                }};
                tempResult.put(deptSubId, temp);

//                不是第一条记录，但是是与前一条记录是相同的诊室，而且是同一天出诊
            } else if (tempSubId == deptSubId && tempDate.equals(date)) {
                //取出该诊室
                HashMap map = (HashMap) tempResult.get(deptSubId);
                //再从诊室中取出出诊计划
                LinkedHashMap plan = (LinkedHashMap) map.get("plan");
                //找出该填出诊医生名单表
                ArrayList doctors = (ArrayList) plan.get(date);
                //把医生名字添加在该天的列表中
                doctors.add(doctorName);
//                不是第一条记录，但是是与前一条记录是相同的诊室，但不是同一天出诊
            } else if (tempSubId == deptSubId && !tempDate.equals(date)) {
                tempDate = date;  //更新日期
//                取出该诊室
                HashMap map = (HashMap) tempResult.get(deptSubId);
//              再从诊室中取出出诊计划
                LinkedHashMap plan = (LinkedHashMap) map.get("plan");
//              创建新的出诊日期列表（另起一行出诊计划），添加该医生的名字
                plan.put(date, new ArrayList<>() {{
                    add(doctorName);
                }});
//                如果该记录与上一条记录不是同诊室
            } else if (tempSubId != deptSubId) {
                tempSubId = deptSubId;
                tempDate = date;
//                直接创建新的诊室对象
                HashMap temp = new HashMap() {{
                    put("deptName", deptName);
                    put("deptSubId", deptSubId);
                    put("deptSubName", deptSubName);
//                    创建新的出诊计划
                    put("plan", new LinkedHashMap<>() {{
                        put(date, new ArrayList<>() {{
                            add(doctorName);
                        }});
                    }});
                }};
//                把新诊室对象也添加到最终的结果集
                tempResult.put(deptSubId, temp);
            }
        }

//        为了前端能循环HashMap中的元素，所以提取所有的元素
        Set<Map.Entry> set = tempResult.entrySet();
//        循环每个元素
        set.forEach(one -> {
            HashMap map = (HashMap) one.getValue();
            LinkedHashMap plan = (LinkedHashMap) map.get("plan");
            /*
             * 提取每个日期，判断出诊计划中是否有该日期
             * 如果出诊计划中每页该日期，说明这天每页医生出诊
             * */
            dateList.forEach(date -> {
                if (!plan.containsKey(date)) {
                    plan.put(date, new ArrayList<>());
                }
            });

//            由于往LinkedHashMap中添加的新元素（空的出诊列表），所以要对所有元素排序
            TreeMap sort = MapUtil.sort(plan, new Comparator() {
                @Override
                public int compare(Object o1, Object o2) {
                    String key1 = (String) o1;
                    String key2 = (String) o2;
                    boolean bool = new DateTime(key1).isAfter(new DateTime(key2));
                    return bool ? 1 : -1;
                }
            });
            map.replace("plan", sort);
        });
//        每个诊室的plan是TreeMap，我们要转换成列表形式，将来才能变成JSON数组
        Collection<HashMap> values = tempResult.values();
        values.forEach(one -> {
            TreeMap plan = (TreeMap) one.get("plan");
//            取出TreeMap中每个元素
            Set<Map.Entry> tempSet = plan.entrySet();
            ArrayList temp = new ArrayList<>();
            tempSet.forEach(entry -> {
                temp.add(new HashMap<>() {{
                    put("date", entry.getKey());
                    put("doctors", entry.getValue());
                }});
            });
            one.replace("plan", temp);
        });
        return JSONUtil.parseArray(values);
    }

    /*
     * 添加门诊日程计划
     * */
    @Autowired
    DoctorWorkPlanScheduleService doctorWorkPlanScheduleService;

    @Override
    public String insert(Map param) {
//        查询选择要添加出诊计划的医生是否存在出诊计划
        Integer id = doctorworkPlanDao.selectIdByDoctorAndSubId(param);
        if (id != null) {
            return OperationMessage.PLAN_EXISTS.toString();
        }
//        保存出诊计划
        DoctorWorkPlan doctorWorkPlan = BeanUtil.toBean(param, DoctorWorkPlan.class);
        doctorWorkPlan.setNum(0);
//        绑定最大挂号人数
        doctorWorkPlan.setMaximum(Integer.parseInt(param.get("totalMaximum").toString()));
        doctorworkPlanDao.insert(doctorWorkPlan);
//        查询出诊计划
        id = doctorworkPlanDao.selectIdByDoctorAndSubId(param);
//        取出医生出诊的各个时间段
        Integer[] slots = (Integer[]) param.get("slots");
        int slotMaximum = Integer.parseInt(param.get("slotMaximum").toString());

        ArrayList<DoctorWorkPlanSchedule> list = new ArrayList<>();
//        根据时间段循环添加DoctorWorkPlanSchedule记录
        for (Integer slot : slots) {
            DoctorWorkPlanSchedule doctorWorkPlanSchedule = BeanUtil.toBean(param, DoctorWorkPlanSchedule.class);
            doctorWorkPlanSchedule.setWorkPlanId(id);
            doctorWorkPlanSchedule.setSlot(slot);
            doctorWorkPlanSchedule.setMaximum(slotMaximum);
            list.add(doctorWorkPlanSchedule);
        }
        doctorWorkPlanScheduleService.insert(list);
        return OperationMessage.PLAN_SAVE_OK.toString();
    }



}